//
// Created by entaoyang@163.com on 2017/10/26.
// Copyright (c) 2017 yet.net. All rights reserved.
//

import Foundation
import SQLite3

public extension Cursor {
    //第一列字符串的集合
    var resultStringSet: Set<String> {
        defer {
            close()
        }
        var set = Set<String>(minimumCapacity: 128)
        while moveToNext() {
            if let s = str(0) {
                set.insert(s)
            }
        }
        return set
    }

    var resultInt: Int? {
        resultLong?.intValue
    }

    var resultLong: Int64? {
        defer {
            close()
        }
        if moveToNext() {
            return int(0)
        }
        return nil
    }

    var resultDouble: Double? {
        defer {
            close()
        }
        if moveToNext() {
            return real(0)
        }
        return nil
    }

    var resultString: String? {
        defer {
            close()
        }
        if moveToNext() {
            return str(0)
        }
        return nil
    }

    var resultBlob: Data? {
        defer {
            close()
        }
        if moveToNext() {
            return blob(0)
        }
        return nil
    }

    var resultExist: Bool {
        defer {
            close()
        }
        if moveToNext() {
            return true
        }
        return false
    }

    var resultObject: YsonObject? {
        defer {
            close()
        }
        if moveToNext() {
            return currentObject()
        }
        return nil
    }

    var resultObjects: YsonArray {
        defer {
            close()
        }
        let yar = YsonArray()
        yar.data.reserveCapacity(128)
        while moveToNext() {
            yar += currentObject()
        }
        return yar
    }

    func eachObject(_ block: (YsonObject) -> Void) {
        defer {
            close()
        }
        while moveToNext() {
            block(currentObject())
        }
    }

    private func currentObject() -> YsonObject {
        let yo = YsonObject()
        for i in 0..<columnCount {
            let ctype = columnType(i)
            let name = columnNames[i]
            switch ctype {
            case SQLITE3_TEXT:
                yo.put(name, str(i))
            case SQLITE_INTEGER:
                yo.put(name, int(i))
            case SQLITE_FLOAT:
                yo.put(name, real(i))
            case SQLITE_BLOB:
                yo.put(name, blob(i))
            case SQLITE_NULL:
                yo.putNull(name)
            default:
                break
            }
        }
        return yo
    }

    func each(_ block: (RowData) -> Void) {
        defer {
            close()
        }
        while moveToNext() {
            block(currentRow())
        }
    }

    private func currentRow() -> RowData {
        var map = RowData()
        for i in 0..<columnCount {
            let ctype = columnType(i)
            let name = columnNames[i]
            switch ctype {
            case SQLITE3_TEXT:
                map[name] = str(i)
            case SQLITE_INTEGER:
                map[name] = int(i)
            case SQLITE_FLOAT:
                map[name] = real(i)
            case SQLITE_BLOB:
                map[name] = blob(i)
            case SQLITE_NULL:
                map[name] = SQLNull.inst
            default:
                break
            }
        }
        return map
    }

    var resultRow: RowData {
        defer {
            close()
        }
        if self.moveToNext() {
            return self.currentRow()
        }
        return [:]
    }

    var resultRows: [RowData] {
        defer {
            close()
        }
        var ls = [RowData]()
        for _ in self {
            ls += self.currentRow()
        }
        return ls
    }

    func decodeOne<V: Decodable>() -> V? {
        resultObject?.toModel()
    }

    func decodeAll<V: Decodable>() -> [V] {
        resultObjects.map {
            $0.toModel()!
        }
//        let yarr: YsonArray = resultObjects
//        var vs: [V] = []
//        vs.reserveCapacity(yarr.count)
//        for yv: YsonValue in yarr {
//            if let v: V = yv.toModel() {
//                vs.append(v)
//            }
//        }
//        return vs
    }
}